#include <string>
#include <map>
#include <pthread.h>
#include <errno.h>
#include <ProcessComposition.h>
#include <CSPConfig.h>
#include <SpuProgram.h>
#include <csp_debug.h>
#include <csp_misc.h>
#include <csp_shared_types.h>
#include <stdio.h>

using namespace std;


CSPConfig::CSPConfig(){
	if( pthread_mutex_init(&mutex, NULL) ){
		perror("Init of mutex failed.");
		exit(1);
	}
	
	char	debug=' ', 
			kill_spu_after_1_job=' ',
			no_mem_reuse=' ',
			clear_spe_mem=' ',
			block_all_dma=' ',
			numthreads=' ';
	#ifdef DEBUG
	debug = 'x';
	#endif
	#ifdef NO_MEM_REUSE
	no_mem_reuse='x';
	#endif
	#ifdef KILL_SPU_AFTER_1_JOB
	kill_spu_after_1_job='x';
	#endif
	#ifdef CLEAR_SPE_MEM
	clear_spe_mem='x';
	#endif
	#ifdef NUMTHREADS
	numthreads='x';
	#else
	#define NUMTHREADS 0
	#endif
	#ifdef BLOCK_ALL_DMA
	block_all_dma='x';
	#endif

	printf("Used macros:\n");
	printf("\t[%c] DEBUG\n", debug);
	printf("\t[%c] NO_MEM_REUSE\n", no_mem_reuse);
	printf("\t[%c] CLEAR_SPE_MEM\n",clear_spe_mem);
	printf("\t[%c] KILL_SPU_AFTER_1_JOB\n", kill_spu_after_1_job);
	printf("\t[%c] NUMTHREADS=%i\n", numthreads, NUMTHREADS);
	printf("\t[%c] BLOCK_ALL_DMA\n", block_all_dma);
	printf("\n");

	size_t pcb_size = sizeof(pcb_t) % 16;
	ASSERT( 0 == pcb_size );
	size_t channel_size = sizeof(csp_channel_t) % 16;
	ASSERT( 0 == channel_size );
}


void 
CSPConfig::add_csp_program(string path, string mnemonic)
{
	unsigned long hash;
	
	SpuProgram *prgm = new SpuProgram(path, mnemonic);
	
	hash = djb2_hash(mnemonic.c_str());

	if(programs.find(hash) != programs.end()){
		perror("Mnemonic already exist!");	
		exit(1);
	}
	if(pthread_mutex_lock(&mutex)){
		perror("Locking failed");
		exit(1);
	}

	programs.insert(pair<long, SpuProgram*>(hash, prgm));

	if(pthread_mutex_unlock(&mutex)){
		perror("Unlocking failed");
		exit(1);
	}
}

SpuProgram * 
CSPConfig::GetProgram(unsigned long hash)
{
	if(pthread_mutex_lock(&mutex)){
		perror("Locking failed");
		exit(1);
	}

	SpuProgram *sp;

	if(programs.find(hash) == programs.end()){
		perror("Mnemonic do not exist!");	
		exit(1);
	}

	sp = programs[hash];

	if(pthread_mutex_unlock(&mutex)){
		perror("Unlocking failed");
		exit(1);
	}

	return sp;
}

SpuProgram* 
CSPConfig::GetProgram(string mnemonic)
{
	if(pthread_mutex_lock(&mutex)){
		perror("Locking failed");
		exit(1);
	}

	unsigned long hash = djb2_hash(mnemonic.c_str());

	if(pthread_mutex_unlock(&mutex)){
		perror("Unlocking failed");
		exit(1);
	}

	return GetProgram(hash);
}

bool 
CSPConfig::ProgramExists(uint64_t hash)
{
	bool res;
	if(pthread_mutex_lock(&mutex)){
		perror("Locking failed");
		exit(-1);
	}

	res = (programs.find(hash) != programs.end());

	if(pthread_mutex_unlock(&mutex)){
		perror("Unlocking failed");
		exit(-1);
	}

	return res;
}


